/**
 * 结构体
 * 数组中的每个元素类型都相同，用结构体实现各元素的类型不同。如，定义学生结构体，学生有学号、姓名、性别、成绩，每个学生结构体有四种成分(四个字段)，数据类型各不相同
 * 定义结构体类型变量的方法
 *  结构体与整型等一样，都是数据类型，都是用来定义变量的。结构体定义变量有如下三种格式。
 * (1)先声明结构体类型再定义变量
 * (2)在声明结构体类型的同时定义变量
 * (3)直接定义结构体类型的变量
 * 10.3结构体变量的引用
 * 引用结构体成员(元素或字段)的格式如下：
<结构体变量>.<成员名>;
 */

#include "stdio.h"
#include "string.h"
#include "malloc.h"
#define LEN sizeof(struct Employee)
#ifdef __WIN32
#define New(p) { \
p=(struct LinkListNode *) malloc(sizeof(struct LinkListNode)); \
p->ch=getchar(); \
p->next=NULL;    \
}
#define New1(p){p=(struct Employee *)malloc(LEN);scanf("%d %s",&p->xh,&p->xm);p->next=NULL;}
#else
//New(p) { \
//p=(struct LinkListNode *) malloc(sizeof(struct LinkListNode)); \
//p->ch=getchar(); \
//p->next=NULL;    \
//}
#define New1(p){p=(struct Employee *)malloc(LEN);scanf("%d %s",&p->xh,&p->xm);p->next=NULL;}
#endif

#define test(x,y) do \
	 {               \
	 	int a = x;   \
	 	int b = y;   \
	 	printf("%d",a); \
	 }while(0);       \
	 int a = x + y;


/*#ifdef __WIN32
#define New(p) {(p)=(node *) malloc(sizeof(node));p->ch=getchar();p->next=NULL;}
#else
#define New1(p) {p=malloc(sizeof(struct node));p->ch=getchar();p->next=NULL;}
#endif*/

/**
 *  定义结构体类型Student，含学号(xh)、姓名(xm)、出生(birthday)，学号int类型，姓名字符串类型，出生是含年月日的结构体类型Date，然后输入学生的相关信息，最后再输出
 */

void test_struct(){
    struct Date{
        int y;
        int m;
        int d;
    };
    struct Student{
        int xh;
        char xm[20];
        struct Date birthday;
    }s;

    //test
    s.xh=1001;
    strcpy(s.xm,"zhangsan");
    s.birthday.y=2014;
    s.birthday.m=12;
    s.birthday.d=11;
    printf("NO:%d|name:%s,birthday:%d/%d/%d \n",s.xh,s.xm,s.birthday.y,s.birthday.m,s.birthday.d);

}
/**
 * 10.4结构体变量的初始化
 * 结构体变量的初始化类似数组的初始化，只是各元素按各自相应类型给初值。如：
 * struct stu s1={5,"张三","男",85.5},s2={6,"李四","女",78.5};
 * @return
 */

//定义结构体类型Stu，含学号(xh)、姓名(xm)，学号int类型，姓名字符串类型，然后输入2个学生的相关信息，再分别输出

void test_struct_1(){
    struct stu{
        int xh;
        char xm[20];
    }s[2];

    //test
//    for(int i=0;i<2;i++){
//        scanf("%d %s",&s[i].xh,&s[i].xm);
//    }
    s[0].xh=10001;
    strcpy(s[0].xm,"zhangsan");
    s[1].xh=10002;
    strcpy(s[1].xm,"lisi");
    for(int i=0;i<2;i++){
        printf("%d %s \n",s[i].xh,s[i].xm);
    }

}

//指向结构体类型数据的指针
//一个结构体变量的指针就是该变量的占据的内存段的起始地址。指针变量也可以用来指向结构体数组中的元素。
//1.指向结构体变量的指针
   /* //指向结构体普通变量的指针的定义类似指向整型普通变量的指针，如
    struct stu *p,s;
    p=&s;
    对结构数据成员的引用方式有如下四种：
    变量引用方式：s.xh,s.xm,s.xb,s.cj
    指针引用方式：(*p).xh,(*p).xm,(*p).xb,(*p).cj
    数组引用方式：p[0].xh,p[0].xm,p[0].xb,(p[0]).cj
    简化表示方式：p->xh,p->xm,p->xb,p->cj
    需注意对结构体成员的自增、自减运算，如
    p->xh++：表示先使用p指向的结构体变量中成员xh的值，用完后使成员xh加1；
    //++p->xh：表示先使p指向的结构体变量中成员xh的值加1，然后再使用成员xh，不同于(++p)->xh。*/
/**
     * //2指向结构体数组的指针
     *函数InputXs(struct stu *p)用指向结构体变量的指针p作为形参实现数据输入，函数OutputXs(struct stu *s)用指向结构体数组的指针s作为形参实现数据输出
     * 指向结构体数组的指针的定义类似指向整型数组的指针，如
        struct stu *p,s[2];
            p=s;
            运行后输入：
4 张三 男 89.5
5 李四 女 78.5
则结果输出：
4,张三,男,89.5
5,李四,女,78.5
     * @return
  */

struct stu{
    int xh;
    char xm[20];
    char xb[4];
    float cj;
};

void inputXs(struct stu *p){
    /*要用指针，否则只能对备份进行输入，不会返回到main()*/
    float x;
    scanf("%d %s %s %f",&p->xh,&p->xm,&p->xb,&x);
    p->cj=x;
}
/*等价于 void OutputXs(struct stu s[]) */
void outputXs(struct stu *p){
    printf("%d,%s,%s,%f \n",p->xh,p->xm,p->xb,p->cj);
}
/**
 * 测试指针指向结构体
 */
void testPoter2Struct(){
    //struct stu s[2];
    struct stu s[2];
    for(int i=0;i<2;i++){
        inputXs(s);
    }
    for(int i=0;i<2;i++){
        outputXs(s);
    }
}

//指针处理链表
/**
 * 前面介绍的数组是一种顺序存储的数据结构，逻辑上相邻的两个元素在物理上也是相邻的，也就是，如果第i个元素存在第i个位置，那么第i+1个元素必定存在第i+1个位置。
 * 而链表是一种链接存储的数据结构，逻辑上相邻的两个元素在物理上一般是不相邻的，相邻元素之间的访问必须通过指针实现，
 * 也就是，若要访问第i个元素，一般必须通过指针先访问第0个元素(表头)，然后通过第0个元素的指针访问第1个元素、再通过第1个元素的指针访问第2个，
 * 以此类推，直到第i个元素。因此，在链接存储中，每个元素(叫结点)至需要包含两方面的信息，即元素本身的信息(叫数值域)和实现元素之间链接关系的指针信息(叫指针域)。
 * 若每个元素只有一个指针域，用于指向其后继结点，这样的链接表叫线性单向链接表，简称单向链表或单链表；若每个元素有两个指针域，分别用于指向其前驱和后继结点，
 * 这样的链接表叫线性双向链接表，简称双向链表或双链表。
 * 由于链表是通过链接构成的，元素的插入和删除只需改变链接关系即可，而不要逐个移动相邻元素，效率高，适合数据动态变化的场合。
 *
 */
//1. 简单链表
//简单链表是单链表中最简单的一种情况，成员中至少有一个数值域用来存元素信息，有一个指针域用来指向一个结构体。这样的结构体叫结点。如：
//struct node
//{char ch;
// struct node *next;
//};
// 定义3个结点，然后链成一个简单链表，最后通过链表输出每个结点的信息
struct Node{
    char ch;  //数据
    struct Node *next; //存储下一个结点的地址
};

//测试链表
void testLinkList(){
    struct Node a,b,c,*p;
    //initization
    a.ch='A';
    b.ch='B';
    c.ch='C';
    a.next=&b;
    b.next=&c;
    c.next=NULL;
    p=&a; //指向头结点
    while(p!=NULL){
        printf("%c ",p->ch);
        p=p->next;
    }

}
/**
 * 处理动态链表所需的函数 void *malloc(unsigned int size);
 * 功能：在内存的动态存储区中分配一个长度为size字节的连续空间。成功，则返回分配空间的起始地址；不成功，则返回空指针(NULL)。
    如：struct node *p;p=(struct node *)malloc(sizeof(struct node));
    或：struct node *p;p=malloc(sizeof(struct node));
    2.calloc函数
    格式：void *calloc(unsigned n,unsigned size);
    功能：在内存的动态存储区中分配n个长度为size字节的连续空间。成功，则返回分配空间的起始地址；不成功，则返回NULL。
    如：struct node *p;p=(struct node *)calloc(10,sizeof(struct node));
    或：struct node *p;p=calloc(10,sizeof(struct node));
    3.free函数
    格式：void free(void *p);
    功能：释放由p指向的内存区，无返回值。
    如：free(p);
    动态分配一般在头文件malloc.h或stdlib.h中定义(具体哪个头文件因编译器而异)，因此，使用时应添加包含命令，如
    #include <malloc.h>或#include<stdlib.h>
 *
 */
//建立动态链表 从表头链入新结点的方法实现创建学生链表并输出链表。
struct LinkListNode{
    char ch;
    struct LinkListNode *next;
};

/**
 * 头插入法创建链表
 */
//void test_dy_link_list(){
//    struct LinkListNode *first=NULL,*p;
//
//    for(int i=0;i<=10;i++){
//        New(p);
//        p->next=first;
//        first=p;
//    }
//    p=first;
//    while(p!=NULL){
//        putchar(p->ch);p=p->next;
//    }
//}

/**
 *
 * 用从表尾链入新结点的方法实现创建学生链表并输出链表。
 */
struct Employee{
    int xh;
    char xm[20];
    struct Employee *next;
};
struct Employee *Create(){
    struct Employee *e1,*e2=NULL,*head=NULL;
    New1(e1);
};
void test_linked_list_back(){

}


/**&
 * 主函数
 * @return
 */
int main7(){
    setvbuf(stdout, NULL, _IONBF, 0); //解决debug时，scanf优于printf捕获的问题
    test_struct();

    test_struct_1();

    //testPoter2Struct();
    //delay(1000000);
    testLinkList();

   // test_dy_link_list();

    return 0;
}